#include "stdafx.h"
#include "execute.h"
#include "includeFTLib.h"
#include "utils.h"
#include "CalcDifference.h"

using namespace std;
using namespace FTLib;

static std::shared_ptr<IBitmapData> LoadFile(ILog* log, int fileNo, const CCmdLineOptions& options, const wstring& filename)
{
	auto bd = FTLib::ReadDataAsFloat32(filename.c_str());

	if (options.GetVerbosityLevel() >= (int)VerbosityLevel::Info)
	{
		log->WriteStdOutLine(L"File#%u: width=%u height=%u pixeltype=%hs", fileNo, bd->GetWidth(), bd->GetHeight(), PixelType2String(bd->GetPixelType()));
	}

	return bd;
}

static bool CheckIfBitmapsMatch(IBitmapData* pB1, IBitmapData* pB2)
{
	if (pB1->GetWidth() != pB2->GetWidth() || pB1->GetHeight() != pB2->GetHeight())
	{
		return false;
	}

	return true;
}

static void PrintDifference(std::function<void(const wchar_t*, va_list)> funcPrintf, const DifferenceInfo& diffInfo)
{
	ILog::argptrConv(funcPrintf, L"mean difference: %lf", diffInfo.meanOfDifferences);
	ILog::argptrConv(funcPrintf, L"std.dev. of difference: %lf", diffInfo.stdDevOfDifferences);
	ILog::argptrConv(funcPrintf, L"min. difference: %lf", diffInfo.minDifference);
	ILog::argptrConv(funcPrintf, L"max. difference: %lf", diffInfo.maxDifference);
}

static bool IsResultWithinLimits(const CCmdLineOptions& options, const DifferenceInfo& diffInfo)
{
	if (!isnan(options.GetMaximumMaxDifference()))
	{
		if (diffInfo.maxDifference > options.GetMaximumMaxDifference())
		{
			return false;
		}
	}

	if (!isnan(options.GetMaximumMeanDifference()))
	{
		if (diffInfo.meanOfDifferences > options.GetMaximumMeanDifference())
		{
			return false;
		}
	}

	return true;
}

int execute(const CCmdLineOptions& options, std::shared_ptr<ILog> log)
{
	auto bd1 = LoadFile(log.get(), 1, options, options.GetFilenameA());
	auto bd2 = LoadFile(log.get(), 2, options, options.GetFilenameB());

	bool b = CheckIfBitmapsMatch(bd1.get(), bd2.get());
	if (b == false)
	{
		if (options.GetVerbosityLevel() >= (int)VerbosityLevel::Error)
		{
			log->WriteStdErrLine(L"Width or height of bitmaps does not match.");
		}

		return true;
	}

	DifferenceInfo info = CalcDifferenceInfo(bd1.get(), bd2.get());

	PrintDifference([&](const wchar_t* fmt, va_list argptr)->void {return log->WriteVStdOutLine(fmt, argptr); }, info);

	if (options.GetIsMaximumGiven() == true)
	{
		b = IsResultWithinLimits(options, info);
		if (b == false)
		{
			return 2;
		}
	}

	return EXIT_SUCCESS;
}